package controllers;

import play.*;
import play.data.validation.Email;
import play.data.validation.Equals;
import play.data.validation.MinSize;
import play.data.validation.Required;
import play.mvc.*;
import play.libs.Mail;

import java.util.*;

import javax.mail.Session;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.apache.commons.mail.SimpleEmail;

import play.cache.*;

import notifiers.Notifier;

import models.*;

import play.libs.Mail;

import org.apache.commons.mail.*;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class Application extends Controller {
	static Integer pageSize = Integer.parseInt(Play.configuration.getProperty(
			"home.pageSize", "10"));
	public static Map<String, Customer> customersMap = new HashMap<String, Customer>();

	// ~~~~~~~~~~~~ @Before interceptors

	@Before
	static void globals() {
		renderArgs.put("connected", connectedCustomer());
		renderArgs.put("pageSize", pageSize);
	}

	public static void index() {
		render();
	}

	public static void home(Long id) {
		Logger.info("Entering home page");
		List<Dish> dishes = Dish.findAll();
		List<Order_item> order_items = Order_item.findAll();
		List<ShoppingOrder> orders = ShoppingOrder.findAll();
		List<Restaurant> restaurants = Restaurant.findAll();
		// List<Customer> customers = Customer.findAll();
		// String test = customers.get(0).toString();
		Customer customer = null;
		if (id != null) {
			customer = Customer.findById(id);
			notFoundIfNull(customer);
			render(dishes, order_items, customer.toString());
		} else {
			render(dishes, order_items, null);
		}

	}

	public static void address(int plz, String address) {
		Logger.info("Validating PLZ and address.");
		validation.required(plz);
		validation.min(plz, 80000);
		validation.max(plz, 81999);
		validation.required(address);
		if (validation.hasErrors()) {
			for (play.data.validation.Error error : validation.errors()) {
				System.out.println(error.message());
				Logger.error(error.message());
			}
			params.flash(); // add http parameters to the flash scope
			validation.keep(); // keep the errors for the next request

			home(null);
		} else {
			if (session.get("plz") != null) {

				int old_plz = Integer.parseInt(session.get("plz").toString());
				if (old_plz != plz) {
					session.put("plz", plz);
					Cache.set(session.getId() + "_shop_order", null, "5mn");
				}
				session.put("address", address);
				Logger.info("PLZ and address validated.");
			} else {
				session.put("plz", plz);
				session.put("address", address);
				Cache.set(session.getId() + "_shop_order", null, "5mn");
				Logger.info("PLZ and address validated.");
			}
			Shop.index();// shopping();
			render(plz);
		}
	}

	public static long createShoppingOrder() {
		try {
			List<Long> orderIDs = Cache.get(session.getId() + "_order_items",
					List.class);
			List<Order_item> orders = new LinkedList<Order_item>();

			for (long orderID : orderIDs)
				orders.add((Order_item) Order_item.findById(orderID));

			ShoppingOrder shop_order = null;

			if (session.get("shopOrderId") == null) {
				shop_order = new ShoppingOrder(orders);
				shop_order.order_status = "undelivered";
				shop_order.save();
				session.put("shopOrderId", shop_order.id);

			} else {
				long id = Long.parseLong(session.get("shopOrderId"));
				shop_order = ShoppingOrder.findById(id);
				shop_order.order_items = orders;
				shop_order.save();

			}

			shop_order.calculatePrice();
			shop_order.save();

			return shop_order.id;
		} catch (Exception e) {
			Logger.error(e,
					"Something went wrong when creating shopping order.");
			return -1;
		}
	}

	public static List<Order_item> getOrderItems() {
		List<Long> orderIDs = Cache.get(session.getId() + "_order_items",
				List.class);
		List<Order_item> orders = new LinkedList<Order_item>();

		for (long orderID : orderIDs)
			orders.add((Order_item) Order_item.findById(orderID));
		return orders;
	}

	public static String updateShoppingOrder(long shopOrderID, String address,
			Date date) {

		try {
			ShoppingOrder shop_order = ShoppingOrder.findById(shopOrderID);
			shop_order.dt = date;
			shop_order.delivery_address = address;
			shop_order.save();

			return "Shopping order updated";
		}

		catch (Exception e) {
			return "Shopping order NOT updated";
		}

	}

	public static String updateOrderStatus(long shopOrderID) {
		try {
			ShoppingOrder shop_order = ShoppingOrder.findById(shopOrderID);
			shop_order.order_status = "delivered";
			shop_order.save();

			return "Status updated";
		}

		catch (Exception e) {
			return "Status NOT updated";
		}

	}

	public static void confirm(String name, String payOption) {
		System.out.println("Name:" + name);
		System.out.println("Pay option:" + payOption);
	}

	public static void signin() {
		render();
	}

	public static void login() {
		render();
	}

	public static void register(@Required @Email String email,
			@Required @MinSize(5) String password,
			@Equals("password") String password2, @Required String name) {
		if (validation.hasErrors()) {
			validation.keep();
			params.flash();
			flash.error("Please verify your data and correct the errors");
			signin();
		} else {
			if (!customersMap.containsKey(email)) {
				Customer customer = new Customer(email, password, name);
				customersMap.put(email, customer);
				try {
					if (Notifier.welcome(customer)) {
						flash.success("Your account is created. You will receive a confirmation e-mail shortly.");
						Properties props = new Properties();
						props.put("mail.smtp.auth", "true");
						props.put("mail.smtp.starttls.enable", "true");
						props.put("mail.smtp.host", "smtp.gmail.com");
						props.put("mail.smtp.port", "587");

						Session session = Session.getInstance(props,
								new javax.mail.Authenticator() {
									protected PasswordAuthentication getPasswordAuthentication() {
										return new PasswordAuthentication(
												"mmunching@gmail.com",
												"munching123");
									}
								});

						Message message = new MimeMessage(session);
						message.setFrom(new InternetAddress(
								"mmunching@gmail.com"));
						message.setRecipients(Message.RecipientType.TO,
								InternetAddress.parse(email));
						message.setSubject("Welcome to Munching Community");
						String link = String
								.format("localhost:9000/application/confirmregistration?uuid="
										+ customer.needConfirmation);
						message.setText("Hey"
								+ customer.name
								+ ", \n Please confirm your registration by clicking on this link: "
								+ link
								+ "\n Thank you very much!\n\n Sincerely, Munching team.");

						Transport.send(message);
						login();
					}
				} catch (Exception e) {
					Logger.error(e, "E-mail could not be sent");
				}
				flash.error("Oops ... (the email cannot be sent)");
				signin();
			} else {
				flash.error("Sorry, email already exists in our database, please modify it.");
				signin();
			}
		}
	}

	public static void confirmRegistration(String uuid) {
		Customer customer = Customer.findByRegistrationUUID(uuid);
		notFoundIfNull(customer);
		customer.needConfirmation = null;
		customer.save();
		connect(customer);
		flash.success("Welcome %s !", customer.name);
		home(customer.id);
	}

	public static void authenticate(String email, String password) {
		Customer customer = Customer.findByEmail(email);
		if (customer == null || !customer.checkPassword(password)) {
			flash.error("Bad email or bad password");
			flash.put("email", email);
			login();
		} else if (customer.needConfirmation != null) {
			flash.error("This account is not confirmed");
			flash.put("notconfirmed", customer.needConfirmation);
			flash.put("email", email);
			login();
		}
		connect(customer);
		flash.success("Welcome back %s !", customer.name);
		home(customer.id);
	}

	public static void resendConfirmation(String uuid) {
		Customer customer = Customer.findByRegistrationUUID(uuid);
		notFoundIfNull(customer);
		try {
			if (Notifier.welcome(customer)) {
				flash.success("Please check your emails ...");
				flash.put("email", customer.email);
				login();
			}
		} catch (Exception e) {
			Logger.error(e, "Mail error");
		}
		flash.error("Oops (the email cannot be sent)...");
		flash.put("email", customer.email);
		login();
	}

	// ~~~~~~~~~~~~ Some utils

	static void connect(Customer customer) {
		session.put("logged", customer.id);
	}

	static Customer connectedCustomer() {
		String customerId = session.get("logged");
		return customerId == null ? null : (Customer) Customer.findById(Long
				.parseLong(customerId));
	}

	public static void logout() {
		flash.success("You've been logged out");
		session.clear();
		home(null);
	}

	public static void Aboutus() {
		render();
	}

	public static void contact() {
		render();
	}

	public static void sendMessageContact(@Required String name,@Required @Email String email, @Required String message) {
		if (validation.hasErrors()) {
			validation.keep();
			params.flash();
			flash.error("Please verify your data and correct the errors");
			contact();
		} else 
		{
			try {
				flash.success(name
						+ ", thank you for contacting us. Your message has been sent.");

				Properties props = new Properties();
				props.put("mail.smtp.auth", "true");
				props.put("mail.smtp.starttls.enable", "true");
				props.put("mail.smtp.host", "smtp.gmail.com");
				props.put("mail.smtp.port", "587");

				Session session = Session.getInstance(props,
						new javax.mail.Authenticator() {
							protected PasswordAuthentication getPasswordAuthentication() {
								return new PasswordAuthentication(
										"mmunching@gmail.com", "munching123");
							}
						});
				Message mensaje = new MimeMessage(session);
				mensaje.setFrom(new InternetAddress("mmunching@gmail.com"));
				mensaje.setRecipients(Message.RecipientType.TO,
						InternetAddress.parse("munching.service@gmail.com"));
				mensaje.setSubject("Testing Subject");
				mensaje.setText("Munching service," + "\n\n Customer: " + name
						+ "\n\n Message: " + message
						+ "\n\n Customer's email: \n\n " + email);
				Transport.send(mensaje);
				contact();
			} catch (Exception e) {
				Logger.error(e, "Error, It was not possible to contact us.");
			}
			contact();	
		}		
	}
	
	
	
	public static void profile() {
		Customer customer = Customer.findById(Long.parseLong(session
				.get("logged")));
		render(customer);
	}

	public static void updates(String email) {
		System.out.println("email: "+email);
		Properties props = new Properties();
		props.put("mail.smtp.auth", "true");
		props.put("mail.smtp.starttls.enable", "true");
		props.put("mail.smtp.host", "smtp.gmail.com");
		props.put("mail.smtp.port", "587");

		try {
			Session session = Session.getInstance(props,
					new javax.mail.Authenticator() {
						protected PasswordAuthentication getPasswordAuthentication() {
							return new PasswordAuthentication(
									"mmunching@gmail.com", "munching123");
						}
					});

			Message message = new MimeMessage(session);
			message.setFrom(new InternetAddress("mmunching@gmail.com"));
			message.setRecipients(Message.RecipientType.TO,
					InternetAddress.parse("mmunching@gmail.com"));
			message.setSubject("New email to subscribe");
			message.setText("New email to subscrbe: " + email);
			Logger.info("Email sent", 0);
			Transport.send(message);
		} catch (AddressException e) {
			Logger.error(e,
					"Error, It was not possible to send email to subscribe.");
		} catch (MessagingException e) {
			Logger.error(e,
					"Error, It was not possible to send email to subscribe.");
		}
		home(null);
	}
	
	public static void changePass(@Required @MinSize(5) String password,
			@Equals("password") String password2){
		if (validation.hasErrors()) {
			validation.keep();
			params.flash();
			flash.error("Please verify your password and correct the errors");
			profile();
		} else {
			Customer customer = Customer.findById(Long.parseLong(session
					.get("logged")));
			customer.setPasswordHash(password);
			customersMap.put(customer.email, customer);
			flash.success("Password modified succesfully!");
		}
		profile();
	}
}